package collect

import (
	"encoding/json"
	"fmt"
	"path/filepath"
	"time"

	// "gitee.com/scjulin/jllib/common"
	// "gitee.com/scjulin/jllib/file"
	"gitee.com/xuesongtao/collect/library"
	"gitee.com/xuesongtao/gotool/base"
	"gitee.com/xuesongtao/gotool/xfile"
	"gitee.com/xuesongtao/protoc-go-valid/valid"
	pslog "gitee.com/xuesongtao/ps-log"
)

var (
	collectProjects []*CollectProject
)

// CollectProject 指定一个 log 进行采集
type CollectProject struct {
	CfgFilename      string    `json:"-"`                                         // 动态构建
	Name             string    `json:"name" valid:"required"`                     // 项目名称
	ProjectDir       string    `json:"project_dir"`                               // 待采集的根目录
	LogDir           string    `json:"log_dir" valid:"required"`                  // 日志相对目录
	WatchType        string    `json:"watch_type" valid:"required,in=(file/dir)"` // 监听类型 file-监听文件 dir-监听目录
	LogRule          LogRule   `json:"log_rule" valid:"required"`                 // 日志规则
	Ignore           bool      `json:"ignore"`                                    // 是否忽略
	ParseStack       bool      `json:"parse_stack"`                               // 是否解析堆栈
	StartLinePattern string    `json:"start_line_pattern"`                        // 每行开始标识符, 正则表达式(注: parse_stack 为 true 才会用到)
	Loop             bool      `json:"loop"`                                      // 是否循环采集
	Tail             bool      `json:"tail"`                                      // 是否实时采集
	Collect          []Collect `json:"collect" valid:"required"`                  // 处理
}

func (c *CollectProject) Key() string {
	return library.GetMd5Str(c.LogDir + c.Name)
}

func (c *CollectProject) GetLogFilename() string {
	return filepath.Join(c.ProjectDir, c.LogDir, c.LogRule.GetLogName())
}

func (c *CollectProject) GetLogDir() string {
	return filepath.Join(c.ProjectDir, c.LogDir)
}

func (c *CollectProject) Valid() error {
	err := valid.Struct(c)
	if err != nil {
		return err
	}
	if xfile.Exists(c.GetLogFilename()) {
		return fmt.Errorf("%q dir is not exist", c.GetLogFilename())
	}
	return nil
}

type LogRule struct {
	Rule  string `json:"rule" valid:"required,in=(yyyy-MM-dd/yyyyMMdd/filename)"` // 日志规则: yyyy-MM-dd(当天时间); yyyyMMdd(当天时间); filename(文件名)
	Value string `json:"value"`                                                   // 值
}

func (l LogRule) GetLogName() string {
	logName := ""
	switch l.Rule {
	case "yyyy-MM-dd":
		logName = time.Now().Format(base.DateFmt) + ".log"
	case "yyyyMMdd":
		logName = time.Now().Format(base.GetTimeFmt(base.DateFmtFlag, "")) + ".log"
	case "filename":
		logName = l.Value
	}
	return logName
}

type Collect struct {
	Title  string   `json:"title"`
	Ignore bool     `json:"ignore"` // 是否忽略
	Target []Targe  `json:"target" valid:"required"`
	TosCfg []TosCfg `json:"tos_cfg" valid:"required"`
}

type Targe struct {
	Content string   `json:"content"` // 目标内容
	Exclude []string `json:"exclude"` // 排除的内容
}

type TosCfg struct {
	Type string                 `json:"type" valid:"required,in=(feishu/email)"` // 类型
	Cfg  map[string]interface{} `json:"cfg"`                                     // 配置
}

// GetWriteTo 获取 pslog 需要 Writer
func (t *TosCfg) GetWriteTo() (pslog.PsLogWriter, error) {
	var wt pslog.PsLogWriter
	switch t.Type {
	case "feishu":
		var data ToFeiShu
		if err := t.initCfgObj(&data); err != nil {
			return nil, err
		}
		data.Init()
		wt = &data
	case "email":
		var data ToEmail
		if err := t.initCfgObj(&data); err != nil {
			return nil, err
		}
		data.Init()
		wt = &data
	default:
		return nil, fmt.Errorf("to cfg %q type is support", t.Type)
	}
	return wt, nil
}

func (t *TosCfg) initCfgObj(data interface{}) error {
	b, _ := json.Marshal(t.Cfg)
	return json.Unmarshal(b, &data)
}
